package spring.cloud.tasks.executor.name_space.executor.task.task_item;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.ThreadFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Setter
@Getter
public class TaskItemExecuteTimeoutTaskSchedulerExecutor {


    private static ConcurrentHashMap<String, ScheduledThreadPoolExecutor> executorIdToScheduledThreadPoolExecutorMap = new ConcurrentHashMap<>();

    private TaskItemExecuteTimeoutTaskSchedulerExecutor() {

    }

    public static synchronized ScheduledThreadPoolExecutor createScheduledThreadPoolExecutor(String executorId) {
        if (!executorIdToScheduledThreadPoolExecutorMap.containsKey(executorId)) {
            ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(Math.max(2, Runtime.getRuntime().availableProcessors() / 2), new ThreadFactory(executorId + "-timeout-watchdog", false));
            scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
            executorIdToScheduledThreadPoolExecutorMap.put(executorId, scheduledThreadPoolExecutor);
            return scheduledThreadPoolExecutor;
        }
        return executorIdToScheduledThreadPoolExecutorMap.get(executorId);
    }

    public static final void shutdownScheduledThreadPoolExecutor(String executorId) {
        if (getScheduledThreadPoolExecutor(executorId) != null) {
            getScheduledThreadPoolExecutor(executorId).shutdown();
            executorIdToScheduledThreadPoolExecutorMap.remove(executorId);
        }
    }

    private static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(String executorId) {
        return executorIdToScheduledThreadPoolExecutorMap.get(executorId);
    }

    public static final void schedule(String executorId, String threadName, int timeoutMinutes) {
        getScheduledThreadPoolExecutor(executorId).schedule(new TaskItemExecuteTimeoutTask(threadName), timeoutMinutes, TimeUnit.MINUTES);
    }

}
